#pragma once

#include <iostream>
#include <string>
#include <cstdlib>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include "Log.hpp"
#include "Common.hpp"
#include "InetAddr.hpp"

namespace Sock_M
{
    // 采用模版方法设计模式
    // 基类（socket）--派生类(TcpSock,UdpSock)继承进行重写
    using namespace Lock_Module;
    using namespace Log_Module;
    using namespace std;
    class Socket;
    using SockPtr = std::shared_ptr<Socket>;

    class Socket
    {
    public:
        virtual ~Socket() = default;
        virtual void Socket_Create() = 0;
        virtual void Socket_option() = 0;
        virtual bool Bind(int port) = 0;
        virtual bool Listen() = 0;
        virtual void close() = 0;
        virtual int Recv(string *out) = 0;
        virtual int Send(const string &in) = 0;
        virtual int Fd() = 0;
        virtual SockPtr Accept(InetAddr *Client) = 0;

        void BulidTcpSock(int port)
        {
            Socket_Create();
            Socket_option();
            Bind(port);
            Listen();
        }
    };

    class Tcp_Socket : public Socket
    {
    private:
        int _sockfd;

    public:
        Tcp_Socket() : _sockfd(gdefaultsockfd)
        {
        }
        Tcp_Socket(int sockfd) : _sockfd(sockfd)
        {
        }
        virtual ~Tcp_Socket() 
        {}
        virtual void Socket_Create() override
        {
            _sockfd=socket(AF_INET,SOCK_STREAM,0);
            if(_sockfd<0)
            {
                LOG(LogLevel::ERROR)<<"create socket error";
                 exit(SCOKET_ERR);
            }
            LOG(LogLevel::INFO)<<"create socket success fd:"<<_sockfd;
        }
        virtual void Socket_option() override
        {
            //在http进行四次挥手的时候，有time_wait状态，需要设置SO_REUSEADDR
            int opt=1;
            int n=setsockopt(_sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
            (void)n;
        }
        virtual bool Bind(int port) override
        {
            if(_sockfd==gdefaultsockfd) return false;
            InetAddr addr(port);
            int n=bind(_sockfd,addr.Netaddr(),addr.NetAddrLen());
            if(n<0)
            {
                LOG(LogLevel::ERROR)<<"bind socket error";
                exit(BIND_ERR);
            }
            LOG(LogLevel::INFO)<<"bind socket success";
            return true;
        }
        virtual bool Listen() override
        {
            if(_sockfd==gdefaultsockfd) return false;
            int n=listen(_sockfd,8);
            if(n<0)
            {
                LOG(LogLevel::ERROR)<<"listen socket error";
                exit(Listen_ERR);
            }
            LOG(LogLevel::INFO)<<"listen socket success";
            return true;
        }
        virtual SockPtr Accept(InetAddr*Client)override
        {
            if(!Client)
            {
                struct  sockaddr_in  peer;
                socklen_t len =sizeof(peer);
                int newfd=accept(_sockfd,Change(&peer),&len);
                if(newfd<0)
                {
                    LOG(LogLevel::WARNING)<<"accept socket error";
                    return nullptr;
                }
                Client->setAddr(peer,len);
                return make_shared<Tcp_Socket>(newfd);
            }
        }
        virtual void close() override
        {
            if(_sockfd!=gdefaultsockfd) return;
            ::close(_sockfd);
        }
        virtual int Recv(string *out) override
        {
            //是输出型参数
            char buf[1024];
            int size=recv(_sockfd,buf,sizeof(buf),0);
            if(size>0)
            {
                buf[size]=0;
                *out=buf;
            }
            return size;
        }

        virtual int Send(const string &in) override
        {
          int size=send(_sockfd,in.c_str(),in.size(),0);
          return size;
        }

         virtual int Fd() override
        {
            return _sockfd;
        }
    };
}